package cn.exrick.xboot.modules.base.serviceimpl;

import cn.exrick.xboot.common.exception.XbootException;
import cn.exrick.xboot.modules.base.enums.*;
import cn.exrick.xboot.modules.base.service.WeChatPayService;
import cn.exrick.xboot.modules.transport.entity.CompanyDepositDetails;
import cn.exrick.xboot.modules.transport.entity.CompanyWarehouses;
import cn.exrick.xboot.modules.transport.entity.DealRecord;
import cn.exrick.xboot.modules.transport.entity.Orders;
import cn.exrick.xboot.modules.transport.mapper.CompanyDepositDetailsMapper;
import cn.exrick.xboot.modules.transport.mapper.CompanyWarehousesMapper;
import cn.exrick.xboot.modules.transport.mapper.DealRecordMapper;
import cn.exrick.xboot.modules.transport.mapper.OrdersMapper;
import cn.hutool.core.util.ObjectUtil;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.github.binarywang.wxpay.bean.notify.*;
import com.github.binarywang.wxpay.bean.request.WxPayOrderQueryV3Request;
import com.github.binarywang.wxpay.bean.request.WxPayRefundV3Request;
import com.github.binarywang.wxpay.bean.request.WxPayUnifiedOrderV3Request;
import com.github.binarywang.wxpay.bean.result.WxPayOrderQueryV3Result;
import com.github.binarywang.wxpay.bean.result.WxPayRefundQueryV3Result;
import com.github.binarywang.wxpay.bean.result.WxPayRefundV3Result;
import com.github.binarywang.wxpay.bean.result.WxPayUnifiedOrderV3Result;
import com.github.binarywang.wxpay.bean.result.enums.TradeTypeEnum;
import com.github.binarywang.wxpay.exception.WxPayException;
import com.github.binarywang.wxpay.service.WxPayService;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.env.Environment;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.servlet.http.HttpServletRequest;
import java.math.BigDecimal;
import java.time.LocalDateTime;


/**
 * <p>
 * 微信支付实现
 * 支付通知结果
 * </p>
 *
 * @author vivi.huang
 * @date 2020-05-17
 */
@Slf4j
@Service
@AllArgsConstructor
public class WeChatPayServiceImpl implements WeChatPayService {

    private Environment environment;
    @Autowired
    private WxPayService wxMaPayService;
    @Autowired
    private OrdersMapper ordersMapper;
    @Autowired
    private DealRecordMapper dealRecordMapper;
    @Autowired
    private CompanyDepositDetailsMapper companyDepositDetailsMapper;
    @Autowired
    private CompanyWarehousesMapper companyWarehousesMapper;




    @Override
    public <T> T createOrderV3(String wxAppCode, TradeTypeEnum tradeType, WxPayUnifiedOrderV3Request request) {
        try {
            if (wxAppCode.equals(WxAppTypeEnum.MA.getCode())){
                return wxMaPayService.createOrderV3(tradeType,request);
            }else {
                throw new XbootException("微信统一下单支付异常,调用支付服务错误");
            }
        } catch (WxPayException wxPayException) {
            log.error("统一下单异常，交易流水单号:[{}]，异常内容:{}", request.getOutTradeNo(), wxPayException);
            throw new XbootException("微信统一下单支付异常");
        }catch (Exception e){
            log.error("统一下单异常，交易流水单号:[{}]，异常内容:{}", request.getOutTradeNo(), e);
            throw new XbootException("微信统一下单支付异常");
        }
    }

    @Override
    public WxPayUnifiedOrderV3Result unifiedOrderV3(String wxAppCode, TradeTypeEnum tradeType, WxPayUnifiedOrderV3Request request) {
        try {
            if (wxAppCode.equals(WxAppTypeEnum.MA.getCode())){
                return wxMaPayService.unifiedOrderV3(tradeType,request);
            }else {
                throw new XbootException("微信统一下单支付异常,调用支付服务错误");
            }
        } catch (WxPayException wxPayException) {
            log.error("统一下单异常，交易流水单号:[{}]，异常内容:{}", request.getOutTradeNo(), wxPayException);
            throw new XbootException("微信统一下单支付异常");
        }catch (Exception e){
            log.error("统一下单异常，交易流水单号:[{}]，异常内容:{}", request.getOutTradeNo(), e);
            throw new XbootException("微信统一下单支付异常");
        }
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public String parseOrderNotifyV3Result(String callback, HttpServletRequest request) {
        try {
            WxPayOrderNotifyV3Result data = wxMaPayService.parseOrderNotifyV3Result(callback,getSignatureHeader(request));
            WxPayOrderNotifyV3Result.DecryptNotifyResult result = data.getResult();
            log.info("执行[支付结果通知回调]:结果为:[{}]",result);
            if ("SUCCESS".equals(result.getTradeState())){
                String dealRecordId = result.getOutTradeNo();
                DealRecord dealRecord = dealRecordMapper.selectById(Long.valueOf(dealRecordId));
                //如果支付信息为订单支付则更新订单状态
                if (dealRecord!= null && DealOrderTypeEnum.ORDER.getCode().equals(dealRecord.getOrderType())){
                    Orders orders = ordersMapper.selectById(dealRecord.getOrderId());
                    if (orders!= null){
                        if (orders.getStatus().equals(OrderStatusEnum.PendingPayment.getValue())){
                            orders.setStatus(OrderStatusEnum.Placed.getValue());
                        }
                        orders.setPaymentStatus(PaymentStatusEnum.PAID.getValue());
                        orders.setPaymentTime(LocalDateTime.now());
                        ordersMapper.updateById(orders);
                    }else {
                        log.error("============微信支付回调，成功，但订单信息已不存在============");
                    }
                }else if(dealRecord!= null && DealOrderTypeEnum.DEPOSIT.getCode().equals(dealRecord.getOrderType())){
                    //新增抵押金明细，并更新仓点抵押金
                    CompanyWarehouses companyWarehouses = companyWarehousesMapper.selectById(dealRecord.getOrderId());
                    if (companyWarehouses!= null){
                        BigDecimal bigDecimal = new BigDecimal(dealRecord.getDealAmount());
                        CompanyDepositDetails companyDepositDetails = getCompanyDepositDetails(companyWarehouses, bigDecimal, dealRecord);
                        companyDepositDetailsMapper.insert(companyDepositDetails);
                        companyWarehouses.setRemainingDeposit(companyWarehouses.getRemainingDeposit().add(bigDecimal.divide(new BigDecimal(100))));
                        companyWarehousesMapper.updateById(companyWarehouses);
                    }else {
                        log.error("============微信支付回调，成功，但仓点信息已不存在============");
                    }
                }else {
                    log.error("支付结果通知-订单状态不符合, 单号:[{}]", dealRecordId);
                    return WxPayNotifyV3Response.success("支付结果通知-订单状态不符合");
                }
                dealRecord.setDealState(DealStateEnum.FINISH.getCode());
                dealRecordMapper.updateById(dealRecord);
                return WxPayNotifyV3Response.success("支付回调成功");
            }else {
                return WxPayNotifyV3Response.fail("支付回调解析失败");
            }
        } catch (WxPayException e) {
            log.error("支付结果通知-解析xml异常", e);
            return WxPayNotifyV3Response.fail(e.getMessage());
        }
    }

    private static CompanyDepositDetails getCompanyDepositDetails(CompanyWarehouses companyWarehouses, BigDecimal bigDecimal, DealRecord dealRecord) {
        CompanyDepositDetails companyDepositDetails = new CompanyDepositDetails();
        companyDepositDetails.setCompanyId(companyWarehouses.getCompanyId());
        companyDepositDetails.setWarehouseId(companyWarehouses.getId());
        companyDepositDetails.setDepositType(DepositTypeEnum.RECHARGE.getValue());
        companyDepositDetails.setAmount(bigDecimal.divide(new BigDecimal(100)));
        companyDepositDetails.setOperator(dealRecord.getCreateBy());
        return companyDepositDetails;
    }

    @Override
    public WxPayOrderQueryV3Result queryOrderV3(WxPayOrderQueryV3Request request) {
        try {
            return wxMaPayService.queryOrderV3(request);
        } catch (WxPayException e) {
            log.error("查询支付异常,单号:[{}]" , request.getOutTradeNo(), e);
            throw new XbootException("查询支付异常");
        }
    }

    @Override
    public WxPayRefundV3Result refundV3(WxPayRefundV3Request request) {
        //退款回调另行配置
        request.setNotifyUrl(environment.getProperty("wechat.pay.refund-notify-url"));
        try {
            return wxMaPayService.refundV3(request);
        } catch (WxPayException e) {
            log.error("申请退款异常, 单号:[{}]", request.getOutTradeNo(), e);
            throw new XbootException("申请退款异常");
        }
    }

    public SignatureHeader getSignatureHeader(HttpServletRequest request){
        String wechatpaySignature = request.getHeader("Wechatpay-Signature");
        String wechatpaySerial = request.getHeader("Wechatpay-Serial");
        String wechatpayTimestamp = request.getHeader("Wechatpay-Timestamp");
        String wechatpayNonce = request.getHeader("Wechatpay-Nonce");
        SignatureHeader signatureHeader = new SignatureHeader();
        signatureHeader.setSignature(wechatpaySignature);
        signatureHeader.setSerial(wechatpaySerial);
        signatureHeader.setTimeStamp(wechatpayTimestamp);
        signatureHeader.setNonce(wechatpayNonce);
        return signatureHeader;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public String parseRefundNotifyV3Result(String callback, HttpServletRequest request) {
        try {
            WxPayRefundNotifyV3Result data = wxMaPayService.parseRefundNotifyV3Result(callback, getSignatureHeader(request));
            WxPayRefundNotifyV3Result.DecryptNotifyResult result = data.getResult();
            log.info("执行[退款结果通知回调]:结果为:[{}]",result);
            if ("SUCCESS".equals(result.getRefundStatus())){
                String dealRecordId = result.getOutTradeNo();
               //todo 补全业务代码
                return WxPayNotifyV3Response.success("退款回调成功");
            }else {
                return WxPayNotifyV3Response.fail("退款回调解析失败");
            }
        } catch (WxPayException e) {
            log.error("退款结果通知-异常{}", e);
            return WxPayNotifyResponse.fail(e.getMessage());
        }
    }

    @Override
    public WxPayRefundQueryV3Result refundQueryV3(String outRefundNo) {
        try {
            return wxMaPayService.refundQueryV3(outRefundNo);
        } catch (WxPayException e) {
            log.error("查询退款异常,单号:[{}]" , outRefundNo , e);
            throw new XbootException("查询退款异常");
        }
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void closeOrderV3(Long dealRecordId) {
        try {
            DealRecord dealRecord = dealRecordMapper.selectById(dealRecordId);
            if(ObjectUtil.isEmpty(dealRecord)){
                throw new XbootException("交易流水不存在。");
            }
            if (dealRecord.getOrderType().equals(DealOrderTypeEnum.ORDER.getCode())){
                Orders orders = ordersMapper.selectById(dealRecord.getOrderId());
                if(ObjectUtil.isEmpty(orders)){
                    throw new XbootException("订单不存在。");
                }else {
                    LambdaUpdateWrapper<Orders> ordersLambdaUpdateWrapper = new LambdaUpdateWrapper<>();
                    ordersLambdaUpdateWrapper
                            .set(Orders::getPaymentUser, null)
                            .set(Orders::getPayInfo, null)
                            .set(Orders::getPaymentTime, null)
                            .eq(Orders::getId, dealRecord.getOrderId());
                    ordersMapper.update(null, ordersLambdaUpdateWrapper);
                }
            }
            dealRecord.setDealState(DealStateEnum.CANCEL.getCode());
            dealRecordMapper.updateById(dealRecord);
            //调取微信取消
            log.info("执行[微信支付订单关闭]:");
            wxMaPayService.closeOrderV3(dealRecordId.toString());
        } catch (WxPayException e) {
            log.error("关闭支付异常, 单号:[{}]", dealRecordId, e);
            throw new XbootException("关闭支付异常");
        }
    }
}
